// (c) 2007 xi8ix. All Rights Reserved.
package org.xi8ix.loader;

import javax.management.*;
import java.lang.management.ManagementFactory;
import java.util.ResourceBundle;
import java.util.MissingResourceException;

/**
 * A tool to load MXBeans and properly assign descriptions and names to objects based on resource property files.
 * The improved naming and descriptions will help create easier to use management systems.
 * Resource files should be stored in a MBeanInfo directory on the classpath. The base name of the resource
 * file is MBeanInfo.
 *
 *
 * @author Iain Shigeoka
 */
public class MXBeanBuilder extends StandardMBean {
    private ResourceBundle resource;

    /**
     * Create a dynamic MBean with the given instance and interface.
     *
     * @param t the object to register
     * @param aClass the MXBean interface to register
     * @throws NotCompliantMBeanException if there was a problem with the MBean format
     */
    public <T> MXBeanBuilder(T t, Class<T> aClass) throws NotCompliantMBeanException {
        super(t, aClass);
        resource = ResourceBundle.getBundle("MBeanInfo."+aClass.getName());
    }

    /**
     * Creates and registers a dynamic MBean with the given name, object instance and interface.
     *
     * @param name the name of the object to register
     * @param t an instance of the object
     * @param aClass the class the object implements
     */
    public static <T> void register(String name, T t, Class<T> aClass) {
        try {
            MXBeanBuilder builder = new MXBeanBuilder(t,aClass);
            ManagementFactory.getPlatformMBeanServer().registerMBean(builder,new ObjectName(name));
        } catch (MBeanRegistrationException e) {
            e.printStackTrace();
        } catch (NotCompliantMBeanException e) {
            e.printStackTrace();
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        } catch (InstanceAlreadyExistsException e) {
            e.printStackTrace();
        }
    }

    /**
     * Creates and registers a singleton dynamic MBean with the given name, object instance and interface.
     * A 'pid' attribute is added to the name using the JMX runtime name for the JVM. Only one dynamic
     * MBean with the same name can be registered as a singleton in this manner.
     *
     * @param name the name of the object to register
     * @param t an instance of the object
     * @param aClass the class the object implements
     */
    public static <T> void registerSingleton(String name, T t, Class<T> aClass) {
        try {
            MXBeanBuilder builder = new MXBeanBuilder(t,aClass);
            String sname = new StringBuilder().append(name).append(",pid=").append(ManagementFactory.getRuntimeMXBean().getName()).toString();
            ManagementFactory.getPlatformMBeanServer().registerMBean(builder,new ObjectName(sname));
        } catch (MBeanRegistrationException e) {
            e.printStackTrace();
        } catch (NotCompliantMBeanException e) {
            e.printStackTrace();
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        } catch (InstanceAlreadyExistsException e) {
            e.printStackTrace();
        }
    }


    protected String getDescription(MBeanInfo mBeanInfo) {
        String desc = "desc";
        try {
            return resource.getString(desc);
        } catch (MissingResourceException m) {
            return super.getDescription(mBeanInfo);
        }
    }

    protected String getDescription(MBeanAttributeInfo mBeanAttributeInfo) {
        String key = new StringBuilder().append("at.").append(mBeanAttributeInfo.getName()).append(".desc").toString();
        try {
            return resource.getString(key);
        } catch (MissingResourceException m) {
            return super.getDescription(mBeanAttributeInfo);
        }
    }

    protected String getDescription(MBeanOperationInfo mBeanOperationInfo) {
        String key = new StringBuilder().append("op.").append(mBeanOperationInfo.getName()).append(".desc").toString();
        try {
            return resource.getString(key);
        } catch (MissingResourceException m) {
            return super.getDescription(mBeanOperationInfo);
        }
    }

    protected String getParameterName(MBeanOperationInfo mBeanOperationInfo, MBeanParameterInfo mBeanParameterInfo, int i) {
        String key = new StringBuilder().append("op.").append(mBeanOperationInfo.getName()).append(".p").append(i).append(".name").toString();
        try {
            return resource.getString(key);
        } catch (MissingResourceException m) {
            return "p"+i;
        }
    }

    protected String getDescription(MBeanOperationInfo mBeanOperationInfo, MBeanParameterInfo mBeanParameterInfo, int i) {
        String key = new StringBuilder().append("op.").append(mBeanOperationInfo.getName()).append(".p").append(i).append(".desc").toString();
        try {
            return resource.getString(key);
        } catch (MissingResourceException m) {
            return super.getDescription(mBeanOperationInfo,mBeanParameterInfo,i);
        }
    }

    protected int getImpact(MBeanOperationInfo mBeanOperationInfo) {
        String key = new StringBuilder().append("op.").append(mBeanOperationInfo.getName()).append(".impact").toString();
        int impact = MBeanOperationInfo.UNKNOWN;
        try {
            String value = resource.getString(key);
            if ("ACTION".equalsIgnoreCase(value)) {
                impact = MBeanOperationInfo.ACTION;
            } else if ("ACTION_INFO".equalsIgnoreCase(value)) {
                impact = MBeanOperationInfo.ACTION_INFO;
            } else if ("INFO".equalsIgnoreCase(value)) {
                impact = MBeanOperationInfo.INFO;
            }
        } catch (MissingResourceException m) {
            impact = super.getImpact(mBeanOperationInfo);
        }
        return impact;
    }
}
